/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "S_摄像机.h"

#include "数学/数学.h"
#include "底层绘图/底层绘图框架.h"
#include "底层绘图/intern/绘图框架.h"
#include <matXX.h>

#include "MBT_Engine.h"





inline Mat44 f_构建摄像机视图矩阵(S_摄像机& camera, Mat44f* 父级变换) {
	
	auto mat = f_构建移动矩阵({0.0f, 0.0f, camera.m_视距});
	auto rx = RotationMatrix(M_角度转弧度(camera.m_变换.rotation.x), { 1.0f,0.0f,0.0f });
	auto ry = RotationMatrix(M_角度转弧度(camera.m_变换.rotation.y), { 0.0f,1.0f,0.0f });
	auto s = ScaleMatrix({ camera.m_缩放.x, camera.m_缩放.y, camera.m_缩放.z });
	
	vec3 eyey_offset = camera.f_get视点偏移();
	if (camera.m_投影模式 == E_投影模式::e_透视) {
		//eyey_offset = camera.m_眼睛偏移;
	}
	else {
		eyey_offset = vec_反向(eyey_offset);
	}
	auto offset = f_构建移动矩阵({ eyey_offset.x, eyey_offset.y, eyey_offset.z });
	auto offset视点 = f_构建移动矩阵(vec_反向(camera.m_视点));


	//camera.m_相机位置矩阵 = mat * offset * (rx * ry) * s * offset视点;
	//camera.m_相机位置矩阵 = (rx * ry);
	
	//camera.m_相机逆矩阵 = f_mat44_Invert(*(Mat44f*)camera.m_相机位置矩阵.columns);
	//camera.m_变换.location = (逆矩阵 * vec3{ 0, 0, 0 });
	camera.m_变换.position = (camera.m_相机逆矩阵 * vec3 { 0, 0, 0 });
	return mat;
}




S_摄像机::S_摄像机(S_设备环境& ctx) : m_Ctx(ctx), S_物体(E_物体类型::t_摄像机){
	m_相机矩阵.resize(2);

	m_GPU参数槽 = {};

	m_分辨率    = { 1920,1080 };
	m_宽高比	= 1.0;
	m_视角		= 45.0;
	m_焦距		= 1;
	m_视距钳制	= { 0.01,  1000000.01 };

	m_视点偏移	= { 0,0,0 };
	m_视点		= { 0.0f,0.0f,0.0f };
	m_视距	= 10.0;

	m_近远端	= { 0.05f, 5000.0f };
	m_投影模式	= E_投影模式::e_透视;
	m_缩放		= { 1.0f,-1.0f, DEF_ForwardDir };

	//f_buf_alloc(S_全局缓存::m_Mat44动态属性, 
	m_投影矩阵 = f_buf_create板载缓存(ctx, sizeof(Mat44f), E_板载缓存类型::e_UBO, 4);

	f_df_allocGPU参数缓存槽(&m_GPU参数槽, 1);
	//m_GPU参数槽.m_GPU布局描述 = S_Engine::g_摄像机GPU布局描述;


	m_最小旋转限制 = { -3.14159, -3.14159, -3.14159 };
	m_最大旋转限制 = { 3.14159, 3.14159, 3.14159 };
	m_旋转限制[0] = false;
	m_旋转限制[1] = false;
	m_旋转限制[2] = false;

	m_采样偏移 = f_mat4_构建移动矩阵({0,0,0});

}

void S_摄像机::f_LookAt(const vec3& eye, const vec3& t, const vec3& up) {
	m_视点 = t;
	m_变换.position = eye;

	vec3 眼睛 = m_变换.position + m_视点偏移;
	vec3 视点 = m_视点 + m_视点偏移;

	m_上方向 = up;
	//m_相机位置矩阵 = f_LookAtMatrix({ 眼睛.x, 眼睛.y, 眼睛.z }, { 视点.x, 视点.y, 视点.z }, { m_上方向.x, m_上方向.y, m_上方向.z } );
	
	m_isUpdate = true;
}

void S_摄像机::f_set透视投影(float32 角度, float32 宽高比, const vec2& 近远端) {
	m_视角 = 角度;
	m_宽高比 = 宽高比;
	m_近远端 = 近远端;
	
	m_isUpdate = true;
}

void S_摄像机::f_set正交投影(const vec2& size) {
	m_相机投影矩阵 = f_mat4_Ortho(0, size.x, size.y, 0, 0, 1000);
	m_投影模式 = E_投影模式::e_正交;
	
	m_正交边界 = size*0.01f;
	m_isUpdate = true;
}




void S_摄像机::f_set位置(float32 x, float32 y, float32 z) {

}

void S_摄像机::f_set累加旋转(float32 x, float32 y, float32 z) {
	m_变换.rotation.x += x;
	m_变换.rotation.y += y;
	m_变换.rotation.z += z;

	m_isUpdate = true;
}

void S_摄像机::f_set缩放(float32 x, float32 y, float32 z) {
	m_视距 += fabs(m_视距)*x*0.12;
	m_视距 = clamp(m_视距, m_视距钳制.x, m_视距钳制.y);
	
	m_isUpdate = true;
}

void S_摄像机::f_set视点偏移(const vec3& offset) {
	m_视点偏移 = offset;
	m_视点偏移.z = 0;
	m_isUpdate = true;
}







void S_摄像机::f_set视角(float32 r) {
	m_视角 = r;
	m_isUpdate = true;
}

void S_摄像机::f_set宽高比(vec2 view) {
	m_宽高比 = view.x / view.y;

	float32 fr = M_角度转弧度(m_视角);
	m_焦距 = (view.y*0.5) / tanf(fr*0.5f);

	m_isUpdate = true;
}

void S_摄像机::f_Update(Mat44f* c) {
	
	std::vector<Mat44f> mat(4);

	if (m_投影模式 == E_投影模式::e_透视) {
		//auto 相机投影 = ProjectionMatrix(m_视角, m_宽高比, m_近远端.x, m_近远端.y);
		//m_相机投影 = *(Mat44f*)&相机投影;

		//(*(mat4*)&m_相机投影) = f_mat4_ProjectionMatrix(m_视角, m_宽高比, 0.001, 3000);
		m_缩放 = { 1.0f, 1.0f, DEF_ForwardDir };

		//float32 f = tanf(M_角度转弧度(m_视角 * 0.5f));
		//float32 zd =  m_近远端.y - m_近远端.x;
		//float32 view[4][4] = { { 1.0f / (m_宽高比 * f), 0.0f, 0.0f, 0.0f },
		//					  { 0.0f, 1.0 / f, 0.0f, 0.0f },
		//					  { 0.0f, 0.0f, -(m_近远端.x + m_近远端.y) / zd, -1.0f },
		//					  { 0.0f, 0.0f, -(2.0f * m_近远端.y * m_近远端.x) / zd, 0.0f } };
		//m_相机投影 = *(Mat44f*)view;

		float32 tanHalfFovy = tan(M_角度转弧度(m_视角) * 0.5f);
		float32 range = (m_近远端.y - m_近远端.x);

		//mat4 matrix{};
		
		//matrix.m0.x = 1.0f / (m_宽高比 * tanHalfFovy);
		//matrix.m1.y = 1.0f / tanHalfFovy;
		//matrix.m2.z = m_近远端.y / range;
		//matrix.m2.w = 1.0f;
		//matrix.m3.z = -m_近远端.x * m_近远端.y / range;

		//mat4 matrix{};
		//float tanHalfFovy = tan(M_角度转弧度(m_视角) * 0.5f);
		//matrix.m0.x = 1.0f / (m_宽高比 * tanHalfFovy);
		//matrix.m1.y = 1.0f / tanHalfFovy;
		//matrix.m2.z = m_近远端.y / (m_近远端.y - m_近远端.x);
		//matrix.m2.w = 1.0f;
		//matrix.m3.z = -(m_近远端.y * m_近远端.x) / (m_近远端.y - m_近远端.x);

		mat4 matrix{};
		matrix.m0.x = 1.0f / (m_宽高比 * tanHalfFovy);
		matrix.m1.y = 1.0f / tanHalfFovy;
		matrix.m2.z = m_近远端.y / range;
		matrix.m2.w = 1.0f;
		matrix.m3.z = -(m_近远端.y * m_近远端.x) / range;

		auto 翻转深度 = f_mat4_构建缩放矩阵({1,1,1});
		m_相机投影矩阵 = *(Mat44f*)&matrix;
		
	}
	else {
		//m_相机投影 = f_OrthographicMatrix(
		//	-m_视点距离 * 0.5 * m_宽高比, 
		//	m_视点距离 * 0.5 * m_宽高比, 
		//	-m_视点距离 * 0.5, 
		//	m_视点距离 * 0.5, 
		//	10000, -1000);
		
		m_相机投影矩阵 = f_mat4_Ortho(
			-m_视距 * 0.5 * m_宽高比,
			m_视距 * 0.5 * m_宽高比,
			-m_视距 * 0.5,
			m_视距 * 0.5,
			10000, -1000);
		m_缩放 = { -1.0f, 1.0f, -DEF_ForwardDir };

		//m_相机投影 = *(Mat44*)&mat[2];
	}

	//f_构建摄像机视图矩阵(*this, c);
	m_相机视图矩阵 = f_camera_计算变换矩阵(*this);
	

	m_相机视图投影矩阵 = (m_相机投影矩阵) * (*(Mat44f*)&m_相机视图矩阵);
	m_旋转矩阵 = f_camera_计算旋转矩阵(*this, false);

	mat[DEF_Camera_Matrix_PV] =  m_相机视图投影矩阵;
	mat[DEF_Camera_Matrix_Rot] = m_旋转矩阵;
	
	mat[DEF_Camera_Matrix_Porj] = m_采样偏移;
	mat[DEF_Camera_Matrix_View] = m_相机视图矩阵;
	
	f_fill板载缓存(m_投影矩阵, mat);
	m_isUpdate = false;
}

void S_摄像机::f_采样偏移(uint32 id, vec2 screenSize) {
	vec2 offset = f_df_视口采样偏移(id) * 0.5 / screenSize * 0.5;
	m_采样偏移 = f_mat4_构建移动矩阵(_Vec3( offset));
	m_采样偏移.m00 = offset.x;
	m_采样偏移.m01 = offset.y;

}

void S_摄像机::f_绘制() {

}

Mat44f f_camera_计算旋转矩阵(const S_摄像机& camera, bool 是否逆) {
	auto X旋转矩阵 = f_mat44_构建行式旋转矩阵({1.0f, 0.0f, 0.0f}, camera.m_变换.rotation.x);
	auto Y旋转矩阵 = f_mat44_构建行式旋转矩阵({0.0f, 1.0f, 0.0f}, camera.m_变换.rotation.y);
	return X旋转矩阵 * Y旋转矩阵;
}

mat4 f_camera_get视图投影(const S_摄像机* camera) {
	return *(mat4*)&(camera->m_相机视图投影矩阵);
}

S_板载缓存* f_camera_get变换矩阵(const S_摄像机* camera) {
	return camera->m_投影矩阵;
}

Mat44f f_camera_计算变换矩阵(const S_摄像机& camera) {
	auto 移动矩阵 = f_mat4_构建移动矩阵({0.0f, 0.0f, camera.m_视距});
	auto X旋转矩阵 = f_mat44_构建行式旋转矩阵({1.0f, 0.0f, 0.0f}, camera.m_变换.rotation.x);
	auto Y旋转矩阵 = f_mat44_构建行式旋转矩阵({0.0f, 1.0f, 0.0f}, camera.m_变换.rotation.y);

	auto 偏移 = f_mat4_构建移动矩阵((camera.m_视点偏移));
	auto 视点 = f_mat4_构建移动矩阵((camera.m_视点));

	auto 相机位置矩阵 = 偏移 * 移动矩阵 * X旋转矩阵 * Y旋转矩阵 * 视点;
	return 相机位置矩阵;
}

